#include "stdafx.h"
#include "common/splitter.h"
#include "resource.h"
#include "PdfTools2.h"
#include <fstream>

class ATL_NO_VTABLE CPdfSplitter :
	public CComObjectRootEx<CComSingleThreadModel>,
	public CComCoClass<CPdfSplitter, &CLSID_PdfSplitter>,
	public ISupportErrorInfo,
	public IDispatchImpl<IPdfSplitter, &IID_IPdfSplitter, &LIBID_PdfTools, /*wMajor =*/ 1, /*wMinor =*/ 0>
{
public:
	CPdfSplitter();

	DECLARE_REGISTRY_RESOURCEID(IDR_PDFSPLITTER)
	DECLARE_NOT_AGGREGATABLE(CPdfSplitter)
	DECLARE_PROTECT_FINAL_CONSTRUCT()

protected:
	BEGIN_COM_MAP(CPdfSplitter)
		COM_INTERFACE_ENTRY(IPdfSplitter)
		COM_INTERFACE_ENTRY(IDispatch)
		COM_INTERFACE_ENTRY(ISupportErrorInfo)
	END_COM_MAP()


	HRESULT FinalConstruct();
	void	FinalRelease();

	// ISupportsErrorInfo
	STDMETHOD(InterfaceSupportsErrorInfo)(REFIID riid);

	// IPdfSplitter
	STDMETHOD(Open)(BSTR path, BSTR password);
	STDMETHOD(SavePages)(BSTR path, ULONG count, ULONG* numbers);
	STDMETHOD(get_PageCount)(ULONG* pVal) throw();
	STDMETHOD(Close)() throw();

	CAutoPtr<Pdf::Splitter>	splitter;
	CAutoPtr<std::ifstream> input;
	CStringA                password;
};

// =====================================================================

inline CPdfSplitter::CPdfSplitter()
{	}

inline HRESULT CPdfSplitter::FinalConstruct()
{	return S_OK;	}

inline void CPdfSplitter::FinalRelease()
{	Close();	}

STDMETHODIMP CPdfSplitter::InterfaceSupportsErrorInfo(REFIID riid)
{
	static const IID* arr[] = { &IID_IPdfSplitter };

	for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); ++i)
		if (InlineIsEqualGUID(*arr[i],riid))
			return S_OK;

	return S_FALSE;
}

STDMETHODIMP CPdfSplitter::Open(BSTR path, BSTR pwd)
{
	try
	{
		CAutoPtr<std::ifstream> newInput( new std::ifstream( CStringA(path), std::ios::binary ) );

		if ( !*newInput )
		{
			Error( ::AtlGetErrorDescription(ERROR_FILE_NOT_FOUND), IID_IPdfSplitter, ERROR_FILE_NOT_FOUND );
			return ERROR_FILE_NOT_FOUND;
		}

		CAutoPtr<Pdf::Splitter> newSplitter;

		try
		{
			newSplitter.Attach( new Pdf::Splitter(*newInput, static_cast<PCSTR>( CStringA(pwd) ), false) );
		}
		catch (Pdf::BrokenPdf &)
		{
			newSplitter.Attach( new Pdf::Splitter(*newInput, static_cast<PCSTR>( CStringA(pwd) ), true) );
		}

		input    = newInput;
		splitter = newSplitter;
		password = CStringA(pwd);

		return S_OK;
	}
	catch (std::exception &e)
	{
		Error( CComBSTR( e.what() ), IID_IPdfSplitter, E_FAIL );
		return E_FAIL;
	}
	catch (...)
	{
		Error( ::AtlGetErrorDescription(E_FAIL), IID_IPdfSplitter, E_FAIL );
		return E_FAIL;
	}
}

STDMETHODIMP CPdfSplitter::SavePages(BSTR path, ULONG count, ULONG* numbers)
{	
	try
	{
		if ( count > 0 && numbers == 0 )
		{
			Error( ::AtlGetErrorDescription(ERROR_INVALID_PARAMETER), IID_IPdfSplitter, ERROR_INVALID_PARAMETER );
			return ERROR_INVALID_PARAMETER;
		}

		if ( splitter == 0)
		{
			Error( ::AtlGetErrorDescription(ERROR_NOT_READY), IID_IPdfSplitter, ERROR_NOT_READY );
			return ERROR_NOT_READY;
		}
		
		std::ofstream output( CStringA(path), std::ios::binary );

		if ( !output )
		{
			Error( ::AtlGetErrorDescription(ERROR_PATH_BUSY), IID_IPdfSplitter, ERROR_PATH_BUSY );
			return ERROR_PATH_BUSY;
		}

		std::vector<int> pages( numbers, numbers + count );

		try
		{
			splitter->savePage(output, pages);
		}
		catch (Pdf::BrokenPdf &)
		{
			splitter = CAutoPtr<Pdf::Splitter>( new Pdf::Splitter(*input, static_cast<PCSTR>(password), true) );
			splitter->savePage(output, pages);
		}

		return S_OK;
	}
	catch (std::exception &e)
	{
		Error( CComBSTR( e.what() ), IID_IPdfSplitter, E_FAIL );
		return E_FAIL;
	}
	catch (...)
	{
		Error( ::AtlGetErrorDescription(E_FAIL), IID_IPdfSplitter, E_FAIL );
		return E_FAIL;
	}
}

STDMETHODIMP CPdfSplitter::Close()
{
	splitter.Free();
	input.Free();
	return S_OK;	
}

STDMETHODIMP CPdfSplitter::get_PageCount(ULONG* pVal)
{	
	if ( splitter == 0)
	{
		Error( ::AtlGetErrorDescription(ERROR_NOT_READY), IID_IPdfSplitter, ERROR_NOT_READY );
		return ERROR_NOT_READY;
	}

	*pVal = splitter->getPageCount();

	return S_OK;	
}

// =====================================================================

OBJECT_ENTRY_AUTO(__uuidof(PdfSplitter), CPdfSplitter)